#include "common.h"
PUBLIC INLINE S4B ActivateATA()
{
   ByteToPort(MASTER8259ACONTROLMASKPORT,(ByteFromPort(MASTER8259ACONTROLMASKPORT) & 0xFB));
   ByteToPort(SLAVE8259ACONTROLMASKPORT ,(ByteFromPort(SLAVE8259ACONTROLMASKPORT ) & 0xBF));
   return ARTIST_ERROR_OK;
}

PUBLIC INLINE S4B ATAWaitDRQ(U1B channel,U4B ticks)
{
   U4B i=0;
   do{
      if(i>ticks)
         break;
      i++;
   }while((ByteFromPort((channel==ATA_PRIMARY?0x1f7:0x177)) & 0x08)==0x00);
   if(i<=ticks)
     return 0;
   
   Assert(i<=ticks);
  return ARTIST_ERROR_UNKNOWN;
}

PUBLIC INLINE S4B ATAWaitBSY(U1B channel,U4B ticks)
{
   U4B i=0;
   do{
      if(i>ticks)
         break;
      i++;
   }while((ByteFromPort((channel==ATA_PRIMARY?0x1f7:0x177)) & 0x80)!=0x00);
   if(i<=ticks)
     return ARTIST_ERROR_OK;
   
   Assert(i<=ticks);
  return ARTIST_ERROR_UNKNOWN;
}

PUBLIC INLINE S4B ATACmd(U1B channel,PATACMD pcmd)
{
  if(channel==ATA_PRIMARY)  /*I abandon using the channel directly just for the safty*/
  {
   ATAWaitBSY(ATA_PRIMARY,1024);
   ByteToPort(0x3F6,pcmd->devicecontrol);
   ByteToPort(0x1F1,pcmd->features);
   ByteToPort(0x1F2,pcmd->sectorcount);
   ByteToPort(0x1F3,pcmd->lbalow);
   ByteToPort(0x1F4,pcmd->lbamid);
   ByteToPort(0x1F5,pcmd->lbahigh);
   ByteToPort(0x1F6,pcmd->device);
   ByteToPort(0x1F7,pcmd->command);
   return ARTIST_ERROR_OK;
  }
  if(channel==ATA_SECONDARY)
  {
   ATAWaitBSY(ATA_SECONDARY,1024);
   ByteToPort(0x376,pcmd->devicecontrol);
   ByteToPort(0x171,pcmd->features);
   ByteToPort(0x172,pcmd->sectorcount);
   ByteToPort(0x173,pcmd->lbalow);
   ByteToPort(0x174,pcmd->lbamid);
   ByteToPort(0x175,pcmd->lbahigh);
   ByteToPort(0x176,pcmd->device);
   ByteToPort(0x177,pcmd->command);
   return ARTIST_ERROR_OK;
  }
  Assert(0);
}

PUBLIC S4B ATAReadPrimarySectors(U4B begin,U1B count,PU1B buffer)
{
    ATACMD cmd;
    SIGNAL signal;
    U2B i;
    MemorySet(&cmd,sizeof(ATACMD),0);
    MemorySet(&signal,sizeof(SIGNAL),0);
    MemorySet(buffer,512*count,0);

    cmd.devicecontrol=0;
    cmd.features=0;
    cmd.sectorcount=(U1B)count;
    cmd.lbalow=(U1B)(begin & 0xFF);
    cmd.lbamid=(U1B)((begin>>8) & 0xFF);
    cmd.lbahigh=(U1B)((begin>>16) & 0xFF);
    cmd.device=0xE0 | ((U1B)((begin>>24) & 0xF));
    cmd.command=0x20;
    ATACmd(ATA_PRIMARY,&cmd);

    signal.sourcepid=INTERRUPT;
    signal.signal=SIGNAL_ATA;
    for(i=0;i<count;i++)
    {

       WaitSignal(&signal);
       ByteFromPort(0x1F7);
       ReadPortWords(0x1f0,512/2,(PU2B)buffer);
       buffer+=512;
    }
    return ARTIST_ERROR_OK;
}

PUBLIC S4B ATAWritePrimarySectors(U4B begin,U1B count,PU1B buffer)
{
    ATACMD cmd;
    SIGNAL signal;
    U2B i;
    MemorySet(&cmd,sizeof(ATACMD),0);
    MemorySet(&signal,sizeof(SIGNAL),0);
    cmd.devicecontrol=0;
    cmd.features=0;
    cmd.sectorcount=(U1B)count;
    cmd.lbalow=(U1B)(begin & 0xFF);
    cmd.lbamid=(U1B)((begin>>8) & 0xFF);
    cmd.lbahigh=(U1B)((begin>>16) & 0xFF);
    cmd.device=0xE0 | ((U1B)((begin>>24) & 0xF));
    cmd.command=0x30;
    ATACmd(ATA_PRIMARY,&cmd);

    signal.sourcepid=INTERRUPT;
    signal.signal=SIGNAL_ATA;

    for(i=0;i<count;i++)
    {
       ATAWaitDRQ(ATA_PRIMARY,10000);
       WritePortWords(0x1f0,512/2,(PU2B)buffer);
       buffer+=512;
       WaitSignal(&signal);
    }
    return ARTIST_ERROR_OK;
}

PUBLIC S4B ATAPrimaryIdentify(PCHAR  ataserialnumber,PU4B   atamaxsectors)
{
    SIGNAL signal;
    signal.sourcepid=INTERRUPT;
    signal.signal=SIGNAL_ATA;
    ATACMD cmd;
    U1B   atapool[512];
    MemorySet(&cmd,sizeof(ATACMD),0);
    cmd.device=0xA0;
    cmd.command=0xEC;
    ATACmd(ATA_PRIMARY,&cmd);
    WaitSignal(&signal);
    ReadPortWords(0x1f0,512/2,(PU2B)atapool);
    MemoryCopy(ataserialnumber,(PCHAR)&atapool[20],20);
    U1B i=0, j=0;         
    for(i=0;i<20;i+=2)
    {
      j=ataserialnumber[i+1];
      ataserialnumber[i+1]=ataserialnumber[i];
      ataserialnumber[i]=j;
      if(ataserialnumber[i]==' ') ataserialnumber[i]='\0';
      if(ataserialnumber[i+1]==' ') ataserialnumber[i+1]='\0';
    }
    *atamaxsectors =*((PU4B)&atapool[120]);
   return ARTIST_ERROR_OK;
}

